package com.heima.article.service.impl;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.heima.article.mapper.ApArticleConfigMapper;
import com.heima.article.mapper.ApArticleContentMapper;
import com.heima.article.mapper.ApArticleMapper;
import com.heima.article.mapper.AuthorMapper;
import com.heima.article.service.ApArticleService;
import com.heima.article.service.GeneratePageService;
import com.heima.common.constants.article.ArticleConstants;
import com.heima.common.constants.article.HotArticleConstants;
import com.heima.common.constants.mq.NewsUpOrDownConstants;
import com.heima.common.constants.wemedia.WemediaConstants;
import com.heima.common.exception.CustException;
import com.heima.feigns.AdminFeign;
import com.heima.feigns.WemediaFeign;
import com.heima.model.admin.pojos.AdChannel;
import com.heima.model.article.dtos.ArticleHomeDTO;
import com.heima.model.article.pojos.ApArticle;
import com.heima.model.article.pojos.ApArticleConfig;
import com.heima.model.article.pojos.ApArticleContent;
import com.heima.model.article.pojos.ApAuthor;
import com.heima.model.article.vos.HotArticleVo;
import com.heima.model.common.dtos.ResponseResult;
import com.heima.model.common.enums.AppHttpCodeEnum;
import com.heima.model.wemedia.pojos.WmNews;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.Date;
import java.util.List;

@Slf4j
@Service
public class ApArticleServiceImpl extends ServiceImpl<ApArticleMapper, ApArticle> implements ApArticleService {
    @Autowired
    WemediaFeign wemediaFeign;
    @Autowired
    AdminFeign adminFeign;
    @Autowired
    StringRedisTemplate redisTemplate;
    @Autowired
    RabbitTemplate rabbitTemplate;
    @Resource
    AuthorMapper authorMapper;
    @Resource
    ApArticleMapper apArticleMapper;
    @Resource
    ApArticleConfigMapper apArticleConfigMapper;
    @Resource
    ApArticleContentMapper apArticleContentMapper;
    @Resource
    GeneratePageService generatePageService;
    @Value("${file.oss.web-site}")
    String webSite;
    @Value("${file.minio.readPath}")
    String realPath;


    @Override
    public void publishArticle(Integer newsId) {
//        校验参数,检查文章状态
        WmNews wmNews = statusCheck(newsId);
//        封装ApArticle
        ApArticle apArticle = getApArticle(wmNews);
//        保存或修改文章
        saveOrUpdateArticle(apArticle);
//        保存管理配置和文章内容
        saveConfigAndContent(apArticle, wmNews);
//        页面静态化
        generatePageService.generateArticlePage(wmNews.getContent(),apArticle);
//        更新wmNews状态
        updateNews(wmNews,apArticle);
//        通知es添加索引
        rabbitTemplate.convertAndSend(NewsUpOrDownConstants.NEWS_UP_FOR_ES_QUEUE,apArticle.getId());
        log.info("文章发布成功，发送到esMQ队列，文章ID为{}",apArticle.getId());
    }

    @Override
    public void DownOrUpArticle(Long articleId, Short enable) {
        ApArticleConfig articleConfig = apArticleConfigMapper.selectOne(new LambdaQueryWrapper<ApArticleConfig>().eq(ApArticleConfig::getArticleId, articleId));
        if (enable==0){
            articleConfig.setIsDown(true);
            rabbitTemplate.convertAndSend(NewsUpOrDownConstants.NEWS_DOWN_FOR_ES_QUEUE,articleId.toString());
        }else {
            articleConfig.setIsDown(false);
            rabbitTemplate.convertAndSend(NewsUpOrDownConstants.NEWS_UP_FOR_ES_QUEUE,articleId.toString());
        }
        apArticleConfigMapper.updateById(articleConfig);

    }

    /**
     * 根据参数加载文章列表
     * @param loadType 1为加载更多  2为加载最新
     * @param dto
     * @return
     */
    @Override
    public ResponseResult load(Short loadType, ArticleHomeDTO dto) {
        if (dto == null){
            log.error("load 方法 ：dto有误,参数为null");
            CustException.cust(AppHttpCodeEnum.PARAM_INVALID);
        }
        if (dto.getSize() == null || dto.getSize()<=0){
            dto.setSize(10);
        }
        // 频道
        if (StringUtils.isBlank(dto.getTag())) {
            dto.setTag(ArticleConstants.DEFAULT_TAG);
        }
        // 时间
        if (dto.getMaxBehotTime() == null) {
            dto.setMaxBehotTime(new Date());
        }
        if (dto.getMinBehotTime() == null) {
            dto.setMinBehotTime(new Date());
        }
        if ((!ArticleConstants.LOADTYPE_LOAD_MORE.equals(loadType)) && !ArticleConstants.LOADTYPE_LOAD_NEW.equals(loadType)){
            log.error("load 方法 ：加载参数loadType有误,参数为{},",loadType);
            CustException.cust(AppHttpCodeEnum.PARAM_INVALID,"加载参数loadType有误");
        }
        List<ApArticle> list = apArticleMapper.getArticleList(loadType,dto);
        for (ApArticle apArticle : list) {
            apArticle.setStaticUrl(realPath+apArticle.getStaticUrl());
        }
        ResponseResult result = ResponseResult.okResult(list);
        result.setHost(webSite);
        return result;
    }

    @Override
    public ResponseResult load2(Short loadtype, ArticleHomeDTO dto) {
        String jsonStr = redisTemplate.opsForValue().get(HotArticleConstants.HOT_ARTICLE_SCORE_BEHAVIOR_QUEUE + dto.getTag());
        if (StringUtils.isNotBlank(jsonStr)){
            List<ApArticle> articleList = JSON.parseArray(jsonStr, ApArticle.class);
            for (ApArticle apArticle : articleList) {
                apArticle.setStaticUrl(realPath+apArticle.getStaticUrl());
            }
            ResponseResult result = ResponseResult.okResult(articleList);
            result.setHost(webSite);
            return result;
        }
        return load(loadtype,dto);
    }

    private void updateNews(WmNews wmNews, ApArticle apArticle) {
        wmNews.setStatus(WemediaConstants.WM_NEWS_PUBLISH_STATUS);
        wmNews.setArticleId(apArticle.getId());
        ResponseResult responseResult = wemediaFeign.updateWmNewsById(wmNews);
        if (responseResult==null || responseResult.getCode()!=0){
            log.error("远程调用updateNewsById时出错,wmNewsId为{}",wmNews.getId());
            CustException.cust(AppHttpCodeEnum.REMOTE_SERVER_ERROR,"远程调用updateNewsById时出错");
        }
    }

    /**
     * 保存article的关联表Config和Content
     * @param apArticle
     * @param wmNews
     */
    private void saveConfigAndContent(ApArticle apArticle, WmNews wmNews) {
        ApArticleConfig apArticleConfig = new ApArticleConfig();
        apArticleConfig.setArticleId(apArticle.getId());
        apArticleConfig.setIsComment(true);
        apArticleConfig.setIsDelete(false);
        apArticleConfig.setIsDown(false);
        apArticleConfig.setIsForward(true);
        apArticleConfigMapper.insert(apArticleConfig);
        log.info("apArticleConfig保存成功，apArticleConfigId为{}",apArticleConfig.getArticleId());
        ApArticleContent apArticleContent = new ApArticleContent();
        apArticleContent.setArticleId(apArticle.getId());
        apArticleContent.setContent(wmNews.getContent());
        apArticleContentMapper.insert(apArticleContent);
        log.info("apArticleContent保存成功，apArticleContentId为{}",apArticleContent.getArticleId());
    }

    /**
     * 对apArticle对象进行保存或者更新
     * @param apArticle
     */
    private void saveOrUpdateArticle(ApArticle apArticle) {
//        校验apArticle是否为新增对象
        if (apArticle.getId()==null){
            apArticle.setCollection(0); // 收藏数
            apArticle.setLikes(0);// 点赞数
            apArticle.setComment(0);// 评论数
            apArticle.setViews(0); // 阅读数
            save(apArticle);
            log.info("新增apArticle成功，apArticleId为{}",apArticle.getId());
        }else {
            apArticleConfigMapper.delete(new LambdaQueryWrapper<ApArticleConfig>().eq(ApArticleConfig::getArticleId, apArticle.getId()));
            apArticleContentMapper.delete(new LambdaQueryWrapper<ApArticleContent>().eq(ApArticleContent::getArticleId, apArticle.getId()));
            updateById(apArticle);
            log.info("更新apArticle成功，apArticleId为{}",apArticle.getId());
        }
    }

    /**
     * 获取ApArticle对象
     * @param wmNews
     * @return
     */
    private ApArticle getApArticle(WmNews wmNews) {
        ApArticle apArticle = new ApArticle();
        BeanUtils.copyProperties(wmNews,apArticle);
        apArticle.setId(wmNews.getArticleId());
        apArticle.setFlag((byte)0); // 普通文章
        apArticle.setLayout(wmNews.getType());// 布局
        ResponseResult<AdChannel> result = adminFeign.findOne(wmNews.getChannelId());
        if (result == null || result.getCode() != 0 ){
            log.error("未查询到频道");
            CustException.cust(AppHttpCodeEnum.PARAM_INVALID);
        }
        apArticle.setChannelName(result.getData().getName());
        ApAuthor apAuthor = authorMapper.selectOne(new LambdaQueryWrapper<ApAuthor>().eq(ApAuthor::getWmUserId, wmNews.getUserId()));
        if (apAuthor == null){
            log.error("未查询到作者,WmNewsID为{}",wmNews.getUserId());
            CustException.cust(AppHttpCodeEnum.PARAM_INVALID);
        }
        apArticle.setAuthorName(apAuthor.getName());
        apArticle.setAuthorId(Long.valueOf(apAuthor.getId()));
        return apArticle;
    }

    /**
     * 获取状态为4或8的WmNews对象
     * @param newsId NewsID
     * @return WmNews对象
     */
    private WmNews statusCheck(Integer newsId) {

        if (newsId == null){
            log.error("请求参数无效，参数为{}",newsId);
            CustException.cust(AppHttpCodeEnum.PARAM_INVALID);
        }
        ResponseResult<WmNews> result = wemediaFeign.findWmNewsById(newsId);
        if (result == null || result.getCode()!=0){
            log.error("未查询到News，NewsId为{}",newsId);
            CustException.cust(AppHttpCodeEnum.PARAM_INVALID);
        }
        WmNews wmNews = result.getData();
        if (wmNews == null){
            log.error("未查询到News，NewsId为{}",newsId);
            CustException.cust(AppHttpCodeEnum.PARAM_INVALID);
        }
        Short status = wmNews.getStatus();
        if ((!WemediaConstants.WM_NEWS_AUTHED_STATUS.equals(status)) && !WemediaConstants.WM_NEWS_MANUALED_STATUS.equals(status)){
            log.error("News状态异常，NewsId为{}",newsId);
            CustException.cust(AppHttpCodeEnum.PARAM_INVALID);
        }
        return wmNews;
    }
}
